﻿// -------------------------------------------------------------------------
//    @FileName         :    NFSessionModule.cpp
//    @Author           :    gaoyi
//    @Date             :    24-8-6
//    @Email            :    445267987@qq.com
//    @Module           :    NFSessionModule
//
// -------------------------------------------------------------------------

#include "NFSessionModule.h"

#include "NFMirrorSessionMgr.h"
#include "NFSessionUtil.h"
#include "proto_access2zone.nanopb.h"
#include "NFServerComm/NFServerCommon/NFIServerMessageModule.h"
#include "NFLogicCommon/NFLogicBindRpcService.h"

#if NF_PLATFORM == NF_PLATFORM_WIN
#else
#include <netinet/in.h>
#endif
#include <NFLogicComm/NFLogicCommon/NFOperatingStatistcsMgr.h>
#include <Player/NFPlayerUtil.h>

#include "NFSession.h"
#include "NFLogicComm/NFServerLogicMessage/proto_need.nanopb.h"
#include "Player/NFPlayer.h"

NFSessionModule::NFSessionModule(NFIPluginManager* p): NFMMODynamicModule(p)
{
}

NFSessionModule::~NFSessionModule()
{
}

int NFSessionModule::Awake()
{
	FindModule<NFIMessageModule>()->AddRpcService<proto_ff::E_ACCESS2ZONE_QUERYUINREQ>(NF_ST_LOGIC_SERVER, this, &NFSessionModule::OnConnectionToken, true);
	FindModule<NFIMessageModule>()->AddRpcService<proto_ff::E_ACCESS2ZONE_START>(NF_ST_LOGIC_SERVER, this, &NFSessionModule::OnConnectionStart, true);
	FindModule<NFIMessageModule>()->AddRpcService<proto_ff::E_ZONE2ACCESS_SETROUTING>(NF_ST_LOGIC_SERVER, this, &NFSessionModule::OnSetRouting, true);

	RegisterServerMessage(NF_ST_LOGIC_SERVER, E_ACCESS2ZONE_TRANSFER);
	RegisterServerMessage(NF_ST_LOGIC_SERVER, E_ACCESS2ZONE_STOP, true);

	return 0;
}

int NFSessionModule::OnHandleServerMessage(uint32_t msgId, NFDataPackage& packet, uint64_t param1, uint64_t param2)
{
	if (!m_pObjPluginManager->IsInited(NF_ST_LOGIC_SERVER))
	{
		NFLogError(NF_LOG_DEFAULT, packet.nParam1, "Logic Server not inited, drop client msg:{}", packet.ToString());
		return -1;
	}

	if (m_pObjPluginManager->IsServerStopping())
	{
		NFLogError(NF_LOG_DEFAULT, packet.nParam1, "Logic Server is Stopping, drop client msg:{}", packet.ToString());
		return -1;
	}

	switch (packet.nMsgId)
	{
	case E_ACCESS2ZONE_STOP:
		{
			OnConnectionStop(msgId, packet, param1, param2);
			break;
		}
	case E_ACCESS2ZONE_TRANSFER:
		{
			OnConnectionMessage(msgId, packet, param1, param2);
			break;
		}
	default:
		{
			NFLogError(NF_LOG_DEFAULT, 0, "Server MsgId:{} Register, But Not Handle, Package:{}", packet.nMsgId, packet.ToString());
			break;
		}
	}
	return 0;
}

int NFSessionModule::OnConnectionStop(uint32_t msgId, NFDataPackage& packet, uint64_t proxyId, uint64_t clientId)
{
	proto_ff::Access2ZoneStop stop;
	CLIENT_MSG_PROCESS_WITH_PRINTF(packet, stop);

	uint32_t sessionId = stop.m_sessionobjid();
	NFSession* pSession = NFSession::GetObjByGlobalId(sessionId);
	CHECK_EXPR(pSession, -1, "CServerUtil::GetSessionObj Failed ID:{}", sessionId);

	uint64_t iConnIdx = pSession->GetConnIndex();
	uint32_t iConnBusID = pSession->GetConnBusId();
	CHECK_EXPR(clientId == iConnIdx, -1, "clientId:{} not match iConnIdx:{}", clientId, iConnIdx);
	CHECK_EXPR(proxyId == iConnBusID, -1, "proxyId:{} not match iConnBusID:{}", proxyId, iConnBusID);

	FindModule<NFIServerMessageModule>()->SendMsgToProxyServer(NF_ST_LOGIC_SERVER, proxyId, E_ACCESS2ZONE_STOP, proto_ff::Zone2AccessStop(), clientId);

	pSession->DisConnect(SESSION_DISCONN_FROM_CLIENT, 0);

	return 0;
}

int NFSessionModule::OnConnectionToken(proto_ff::Access2ZoneQueryUinReq& request, proto_ff::Access2ZoneQueryUinRes& respone, uint64_t proxyId, uint64_t clientId)
{
	NFLogDebug(NF_LOG_DEFAULT, clientId, "query uin, proxyId:{} clientId:{} ip:{}", proxyId, clientId, request.m_playerip());
	NFServerConfig* pConfig = FindModule<NFIConfigModule>()->GetAppConfig(NF_ST_LOGIC_SERVER);
	NF_ASSERT(pConfig);

	NFConnectionInfo stConnInfo;
	stConnInfo.m_iConnIdx = clientId;
	stConnInfo.m_iConnBusID = proxyId;
	proto_ff::AccountInfo accountInfo;
	bool ok = accountInfo.ParsePartialFromString(request.m_accountinfo());
	if (!ok)
	{
		LOGSVR_ERROR("Parse account_info From String failed:" << request.m_accountinfo());
		FindModule<NFIServerMessageModule>()->SendMsgToProxyServer(NF_ST_LOGIC_SERVER, proxyId, E_ACCESS2ZONE_STOP, proto_ff::Zone2AccessStop(), clientId);
		respone.set_m_ret(proto_ff::ERR_CODE_SYSTEM_ERROR);
		return 0;
	}

	NFLogDebug(NF_LOG_DEFAULT, clientId, "query uin, proxyId:{} clientId:{} accountInfo:{}", proxyId, clientId, accountInfo.Utf8DebugString());

	stConnInfo.m_szOpenID = accountInfo.account_id();
	stConnInfo.m_chPlatformType = accountInfo.account_type();

	LOGSVR_DEBUG("account_type=" << accountInfo.account_type() << ", openid=" << accountInfo.account_id()
		<< ", plat_type=" << accountInfo.plat_type() << ", token=" << request.m_token()
		<< ", ip=" << request.m_playerip());

	if (!proto_ff::eAccountType_IsValid(accountInfo.account_type()))
	{
		FindModule<NFIServerMessageModule>()->SendMsgToProxyServer(NF_ST_LOGIC_SERVER, proxyId, E_ACCESS2ZONE_STOP, proto_ff::Zone2AccessStop(), clientId);
		respone.set_m_ret(proto_ff::ERR_CODE_SYSTEM_ERROR);
		return 0;
	}

	if (accountInfo.account_type() != proto_ff::E_Account_Type_Local && !pConfig->IsNoToken)
	{
		if (accountInfo.plat_type() != proto_ff::E_PLAT_ANDROID &&
			accountInfo.plat_type() != proto_ff::E_PLAT_IOS)
		{
			FindModule<NFIServerMessageModule>()->SendMsgToProxyServer(NF_ST_LOGIC_SERVER, proxyId, E_ACCESS2ZONE_STOP, proto_ff::Zone2AccessStop(), clientId);
			respone.set_m_ret(proto_ff::ERR_CODE_SYSTEM_ERROR);
			return 0;
		}

		/*proto_ff::Proto_SvrPkg pkg_2;
		proto_ff::Proto_GARoleLoginAuthenticationReq* pGSReq = pkg_2.mutable_login_auth_req();

		pkg_2.set_svr_msg_id(proto_ff::E_GA_LOGIN_AUTHENTICATION_REQ);
		pGSReq->mutable_info()->set_connid(clientId);
		//pGSReq->mutable_info()->set_objid(access_bus_head.m_objid);
		pGSReq->mutable_info()->set_conn_bus_id(proxyId);
		pGSReq->mutable_info()->mutable_info()->CopyFrom(accountInfo);
		pGSReq->set_token(request.m_token());
		//pGSReq->set_ip(request.m_playerip());
		//CPacketSendUtil::SendToFuncSvr(FUNC_AUTHSVR, &pkg_2);*/
	}
	else
	{
		if (accountInfo.plat_type() != proto_ff::E_PLAT_ANDROID &&
			accountInfo.plat_type() != proto_ff::E_PLAT_IOS &&
			accountInfo.plat_type() != proto_ff::E_PLAT_WP)
		{
			FindModule<NFIServerMessageModule>()->SendMsgToProxyServer(NF_ST_LOGIC_SERVER, proxyId, E_ACCESS2ZONE_STOP, proto_ff::Zone2AccessStop(), clientId);
			respone.set_m_ret(proto_ff::ERR_CODE_SYSTEM_ERROR);
			return 0;
		}
		uint64_t uin = (uint64_t)BKDRHash(request.m_accountinfo().data(), request.m_accountinfo().size());

		LOGSVR_DEBUG("uin=" << uin << ", account_id=" << accountInfo.account_id().c_str() << ", len=" << strlen(accountInfo.account_id().c_str()));

		respone.set_m_uin(uin);
	}

	respone.set_m_ret(0);
	return 0;
}

int NFSessionModule::OnConnectionStart(proto_ff::Access2ZoneStart& request, proto_ff::Access2ZoneStartRes& respone, uint64_t proxyId, uint64_t clientId)
{
	NFLogDebug(NF_LOG_DEFAULT, clientId, "query uin, proxyId:{} clientId:{} ip:{}", proxyId, clientId, request.m_playerip());
	NFServerConfig* pConfig = FindModule<NFIConfigModule>()->GetAppConfig(NF_ST_LOGIC_SERVER);
	NF_ASSERT(pConfig);

	NFConnectionInfo stConnInfo;
	NFSession* pSession = nullptr;
	pSession = NFSession::CreateObj();
	if (pSession == nullptr)
	{
		FindModule<NFIServerMessageModule>()->SendMsgToProxyServer(NF_ST_LOGIC_SERVER, proxyId, E_ACCESS2ZONE_STOP, proto_ff::Zone2AccessStop(), clientId);
		respone.set_m_ret(proto_ff::ERR_CODE_SYSTEM_ERROR);
		NFLogError(NF_LOG_DEFAULT, clientId, "CIDRuntimeClass::CreateObj Failed");
		return 0;
	}

	stConnInfo.m_iConnIdx = clientId;
	stConnInfo.m_iConnBusID = proxyId;
	stConnInfo.m_iLoginIP = request.m_playerip();
	stConnInfo.m_ullUin = request.m_uin();
	stConnInfo.m_dwConnTime = NF_ADJUST_TIMENOW();

	proto_ff::AccountInfo accountInfo;
	bool ok = accountInfo.ParseFromArray(request.m_accountinfo().data(), request.m_accountinfo().size());
	if (!ok)
	{
		LOGSVR_ERROR("Parse account_info From String failed:" << request.m_accountinfo());
		FindModule<NFIServerMessageModule>()->SendMsgToProxyServer(NF_ST_LOGIC_SERVER, proxyId, E_ACCESS2ZONE_STOP, proto_ff::Zone2AccessStop(), clientId);
		respone.set_m_ret(proto_ff::ERR_CODE_SYSTEM_ERROR);
		return 0;
	}

	stConnInfo.m_szOpenID = accountInfo.account_id();
	stConnInfo.m_chPlatformType = accountInfo.account_type();
	stConnInfo.m_iDeviceType = accountInfo.plat_type();
	LOGSVR_DEBUG("account_type=" << accountInfo.account_type() << ", openid=" << accountInfo.account_id()
		<< ", plat_type=" << accountInfo.plat_type() << ", m_ullUin=" << stConnInfo.m_ullUin
		<< ", ip=" << stConnInfo.m_iLoginIP.data());

	pSession->Connect(&stConnInfo);

	respone.set_m_sessionobjid(pSession->GetGlobalId());
	respone.set_m_ret(0);
	return 0;
}

uint32_t NFSessionModule::BKDRHash(const void* key, int keyLen)
{
	uint8_t* pKey = NULL;
	uint8_t* pEnd = NULL;
	uint32_t seed = 131; //  31 131 1313 13131 131313 etc..
	uint32_t hash = 0;

	pEnd = (uint8_t*)key + keyLen;
	for (pKey = (uint8_t*)key; pKey != pEnd; pKey++)
	{
		hash = hash * seed + (*pKey);
	}

	return hash;
}

int NFSessionModule::OnConnectionMessage(uint32_t msgId, NFDataPackage& packet, uint64_t sessionId, uint64_t param2)
{
	NFrame::Proto_FramePkg pkg;
	CLIENT_MSG_PROCESS_WITH_PRINTF(packet, pkg);

	NFDataPackage tempPackage = packet;
	tempPackage.nMsgId = pkg.msg_id();
	tempPackage.nMsgLen = pkg.msg_data().size();
	tempPackage.nMsgSeq = pkg.disp_info().seq();
	tempPackage.mModuleId = pkg.module_id();
	tempPackage.nBuffer = (char*)pkg.msg_data().data();
	tempPackage.nParam1 = sessionId;
	FindModule<NFIMessageModule>()->OnHandleMessage(tempPackage);
	return 0;
}

int NFSessionModule::OnSetRouting(proto_ff::Access2ZoneSetRoutingRpcReq& request, proto_ff::Zone2AccessSetRoutingRpcRsp& respone, uint64_t proxyId, uint64_t clientId)
{
    int iRetCode = 0;
    do
    {
        int sessionId = request.m_sessionobjid();
        auto pSession = NFSessionUtil::GetSessionObj(sessionId);
        if (pSession == nullptr)
        {
            LOG_ERR(0, -1, "GetSessionObj Failed sessionId:{}", sessionId);
            break;
        }

        if (pSession->GetConnIndex() != clientId)
        {
            iRetCode = -1;
            LOG_ERR(0, iRetCode, "ClientId not match sessionId:{} clientId:{} m_iConnIdx:{}", sessionId, clientId, pSession->GetConnIndex());
            break;
        }

        if (pSession->GetConnBusId() != proxyId)
        {
            iRetCode = -1;
            LOG_ERR(0, iRetCode, "ProxyId not match sessionId:{} proxyId:{} m_iConnBusID:{}", sessionId, proxyId, pSession->GetConnBusId());
            break;
        }

        if (!pSession->IsLockedLoginMirror())
        {
            iRetCode = -1;
            LOG_ERR(0, iRetCode, "Session IsLockedLoginMirror Failed sessionId:{}", sessionId);
            break;
        }

        uint64_t roleId = pSession->GetLockedLoginMirrorRoleId();

        iRetCode = NFMirrorSessionMgr::Instance()->UnLockLoginMirror(roleId, pSession->GetGlobalId());
        if (iRetCode != 0)
        {
            LOG_ERR(roleId, iRetCode, "UnLockLoginMirror failed, roleId:{} sessionId:{}", roleId, sessionId);
            break;
        }
    } while (false);

    respone.set_result(iRetCode);
    return 0;
}
